<?php

namespace Common\Model;

use Think\Model;

class UserModel extends Model
{
    protected $_validate = array(
        array('username', 'checklength', '用户名长度必须在3-18位之间！', 0, 'callback', 3, array(3, 18)),
        array('password', 'require', '用户名或密码不能为空！', 0),
    );
    protected $_auto = array(
        array('gold', '0'),
        array('exp', '0'),
        array('exp_lv', '1'),
        array('reg_time', 'time', 1, 'function'),
        array('reg_ip', 'get_client_ip', 1, 'function'),
        array('reg_address', 'get_client_ip_txt', 1, 'function'),

    );

    /**
     * 获取会员信息
     *
     * @param mixed $u
     * @param bool  $fill 是否填充用户附加信息
     * @param int   $type 1-UID 2-手机 3-用户名 4-openid
     * @return mixed
     */
    public function get_user_one($u = '', $fill = false, $type = 1)
    {
        $map = array();
        if ($type == 1) {
            $map['uid'] = intval($u);
        }
        if ($type == 2) {
            if (!preg_match("/^1[23456789]{1}\d{9}$/", $u)) {
                return false;
            }
            $map['mobile'] = $u;
        }
        if ($type == 3) {
            $map['username'] = trim($u);
        }
        if ($type == 4) {
            $map['openid'] = trim($u);
        }
        $info = $this->where($map)->find();
        if ($fill) {
            $info = $this->auto_user_fill($info);
        }
        return $info;
    }

    /**
     * 登陆
     *
     * @param array $user
     * @param int   $u
     * @param int   $logtype
     * @return bool
     */
    public function user_login($user = array(), $u = null, $logtype = 1)
    {
        if (!empty($user)) {
            D('LogLogin')->add_login_log($user['uid']);
            D('UserMsg')->update_user_msg($user['uid']);

            return $this->make_session($user['uid'], $user);
        } else {
            $user = $this->get_user_one($u, false, $logtype);
            return $this->user_login($user, $u);
        }
    }

    /**
     * 检查账号/手机号/和密码(明码检测)
     *
     * 验证成功返回用户信息，否则返回False
     *
     * @param string $username 用户名或者手机号
     * @param string $password
     * @return array|bool
     */
    public function verify_username_password($username = '', $password = '')
    {
        if (preg_match("/^1[23456789]{1}\d{9}$/", $username)) {
            $map['mobile'] = $username;
        } else {
            $map['username'] = $username;
        }
        $info = $this->where($map)->find();
        if (empty($info)) {
            return false;
        } else {
            $pwdmd5 = get_pwdmd5($password, $info['pwd_hash']);
            if ($pwdmd5 == $info['password']) {
                return $info;
            } else {
                return false;
            }
        }
    }

    /**
     * 是否登陆 [如果设置了自动登录，则会自动登录]
     *
     * @return bool
     */
    public function is_login()
    {
        if (session('?ytata.uid') && session('?ytata.username')) {
            return true;
        } else {
            return $this->verify_cookie();
        }
    }

    /**
     * 判断管理员是否已登录
     *
     * 可根据登录SESSION或者COOKIE验证
     *
     * @return bool
     */
    public function is_admin_login()
    {
        if (session('?ytata.uid') && session('?ytata.username') && session('ytata.isadmin') > 0) {
            return true;
        } else {
            return $this->verify_cookie(true);
        }
    }

    /**
     * 注册
     *
     * @param string $username
     * @param string $mobile
     * @param string $password
     * @param bool   $send_sms
     * @param string $bind
     * @return mixed
     */
    public function user_reg($username = '', $mobile = '', $openid = '', $password = '', $send_sms = false, $bind = '')
    {
        if (C('YTATA_REG_CLOSE') == '1') {
            $return['status'] = 0;
            $return['content'] = '会员注册临时关闭，请您稍后再试！';
            return $return;
        }
        $SMSopen = C('YTATA_SMS_OPEN');
        $username = trim($username);
        $mobile = trim($mobile);
        $openid = trim($openid);
        $password = trim($password);
        $data['pwd_hash'] = randstr();
        if (empty($username) && empty($mobile) && empty($openid)) {
            $return['status'] = 0;
            $return['content'] = '用户名、手机号和openid至少填写一项';
            return $return;
        }
        if (!empty($password)) {
            $data['password'] = get_pwdmd5($password, $data['pwd_hash']);
        } else {
            $password = rand(100000, 999999);
            $data['password'] = get_pwdmd5($password, $data['pwd_hash']);
        }
        if (!empty($mobile) && !preg_match("/^1[23456789]{1}\d{9}$/", $mobile)) {
            $return['status'] = 0;
            $return['content'] = '手机号格式错误';
            return $return;
        }
        if (!empty($mobile) && $this->get_user_one($mobile, false, 2)) {
            $return['status'] = 0;
            $return['content'] = '手机号已经存在，请选择其他手机号注册';
            return $return;
        }
        if (!empty($username) && $this->get_user_one($username, false, 3)) {
            $return['status'] = 0;
            $return['content'] = '用户名已经存在';
            return $return;
        }
        if (!empty($openid) && $this->get_user_one($openid, false, 4)) {
            $return['status'] = 0;
            $return['content'] = 'openid已存在';
            return $return;
        }
        if (empty($username)) {
            $th = C('YTATA_REG_PRE_MOB');
            $th = $th ? $th : 'mb';
            $randnum = $mobile ? $mobile : uniqid();
            $username_rand = $th . substr($randnum, -8, 8) . substr(uniqid(), -4, 4);
        }
        $data['username'] = $username ? $username : $username_rand;
        $data['mobile'] = $mobile;
        $data['openid'] = $openid;
        $data['nick'] = trim(session('ytatatmp.nickname'));
        $data['avatar'] = trim(session('ytatatmp.headimgurl'));
        $data['isadmin'] = 0;
        $data['auth'] = 0;
        $data['entrance'] = C('YTATA_ENTRANCE');
        if (!$addarr = $this->create($data, 1)) {
            $return['status'] = 0;
            $return['content'] = $this->getError() . $data['username'];
            return $return;
        }
        $uid = $this->add($addarr);
        //第三方绑定
        if (!empty($bind)) {
            $bind_data['uid'] = $uid;
            $bind_data['keyid'] = $bind['bind_keyid'];
            $bind_data['type'] = $bind['bind_type'];
            $bind_data['bindingtime'] = time();
            M('UserBind')->add($bind_data);
            session('user_bind_info', null);
        }
        $data['uid'] = $uid;
        $this->user_login($data, $uid);//通过UID登录
        D('Task')->exe_first_reg($uid);//首次注册赠送
        D('UserMsg')->update_user_msg($uid, 2);//发送注册消息
        if ($send_sms && $SMSopen && !empty($mobile)) {
            $params['sitename'] = C('YTATA_SITE_NAME');
            $params['username'] = $username ? $username : $mobile;
            $params['password'] = $password;
            $send = send_sms($mobile, $params, 'reg');
        }
        $return['status'] = 1;
        $return['content'] = '注册成功！';
        return $return;
    }

    /**
     * 通过cookie检查用户名
     *
     * 如果cookie存在并通过用户有效性验证，则记录cookie用户登录Session,否则清空用户Cookie和Session
     *
     * @return bool
     */
    public function verify_cookie($isadmin = false)
    {
        $username = cookie('ytata_username');
        $password = cookie('ytata_password');
        if (empty($username) || empty($password)) {
            return false;
        } else {
            $map['username'] = $username;
            $map['password'] = $password;
            $info = $this->where($map)->find();
            if (!empty($info)) {
                if ($isadmin === false || $info['isadmin'] > 0) {
                    return $this->make_session('', $info);
                }
                return false;
            } else {
                $this->clear_session();
                return false;
            }
        }
    }

    /**
     * 生成Session
     *
     * @param int   $uid
     * @param array $user
     * @return bool
     */
    public function make_session($uid = null, $user = array())
    {
        if (!empty($user)) {
            session('ytata.uid', $user['uid']);
            session('ytata.username', $user['username']);
            session('ytata.mobile', $user['mobile']);
            session('ytata.isadmin', $user['isadmin']);
            session('ytata.auth', $user['auth']);
            return true;
        } else {
            $uid = intval($uid);
            $user = $this->get_user_one($uid);
            if (!$user) {
                return false;
            }
            return $this->make_session(null, $user);
        }
    }

    /**
     * 清除session
     */
    public function clear_session()
    {
        session('ytata.uid', null);
        session('ytata.username', null);
        session('ytata.isadmin', null);
        session('ytata.auth', null);
        cookie('ytata_username', null);
        cookie('ytata_password', null);
        return true;
    }

    /**
     * 修改密码
     *
     * @param        $uid
     * @param string $pwd
     * @return bool
     */
    public function edit_pwd($uid = '', $pwd = '')
    {
        $user = $this->get_user_one($uid);
        $map['uid'] = intval($uid);
        $map['password'] = get_pwdmd5($pwd, $user['pwd_hash']);
        $this->save($map);
        return true;
    }

    /**
     * 更新用户的openid
     *
     * @param string $uid
     * @return bool
     */
    public function update_user_openid($uid = '', $openid = '')
    {
        $map['uid'] = intval($uid);
        $map['openid'] = trim($openid);
        $this->save($map);
        return true;
    }

    /**
     * 更新用户采纳率
     *
     * @param string $uid
     * @return bool
     */
    public function update_acc_rate($uid = '')
    {
        $map['uid'] = intval($uid);
        $map['acc_rate'] = D('Answer')->acc_rate($map['uid']);
        $this->save($map);
        return true;
    }

    /**
     * 更新用户文章总数或问答总数
     *
     * @param array|int $uid
     * @param int       $type 更新类型 1-问题 2-文章 3-讨论
     * @return bool
     */
    public function update_count($uid, $type = 1)
    {
        $uid = is_array($uid) ? $uid : array($uid);
        foreach ($uid as $u) {
            if ($type == 1) {
                $count = D('Question')->count_question($u);
                $map['uid'] = intval($u);
                $map['count_question'] = intval($count);
                $this->save($map);
            }
            if ($type == 2) {
                $count = D('Article')->count_article($u);
                $map['uid'] = intval($u);
                $map['count_article'] = intval($count);
                $this->save($map);
            }
            if ($type == 3) {
                $count = D('Bbs')->count_bbs($u);
                $map['uid'] = intval($u);
                $map['count_bbs'] = intval($count);
                $this->save($map);
            }
        }
        return true;
    }

    /**
     * 更新会员最后登录时间
     *
     * @param array $arr
     */
    public function edit_login_lastlog($arr = null)
    {
        $datalog['last_login_time'] = $arr['login_time'];
        $datalog['last_login_ip'] = $arr['login_ip'];
        $datalog['last_login_address'] = $arr['login_address'];
        $this->where('uid=' . $arr['uid'])->save($datalog);//更新用户表最后登录时
    }

    /**
     * 更新擅长
     *
     * @param string $uid
     * @param string $specialty
     */
    public function edit_specialty($uid = '', $specialty = '')
    {
        $map['uid'] = intval($uid);
        $data['specialty'] = trim($specialty);
        $this->where($map)->save($data);
    }

    /**
     * 更新答案总数
     *
     * @param string $uid
     * @return bool
     */
    public function edit_answercount($uid = '')
    {
        $map['uid'] = intval($uid);
        $map['count_answer'] = D('Answer')->count_answer($map['uid']);
        $this->save($map);
        return true;
    }

    /**
     * 更新会员积分和经验
     *
     * @param string $type     更新类型 '1'-gold '2'-exp
     * @param int    $uid
     * @param int    $var      更新数量
     * @param string $logtxt   日志描述
     * @param bool   $addition 更新方向 true-增加 false-减少
     * @return bool
     */
    public function edit_user_gold($type = '1', $uid, $var = 0, $logtxt = '', $addition = true)
    {
        $type = intval($type);
        $uid = intval($uid);
        $userinfo = $this->get_user_one($uid);
        if ($type == '1') {
            $udata['gold'] = $addition ? ($userinfo['gold'] + $var) : ($userinfo['gold'] - $var);
        }
        if ($type == '2') {
            $udata['exp'] = $addition ? ($userinfo['exp'] + $var) : ($userinfo['exp'] - $var);
            //更新会员等级
            $udata['exp_lv'] = D('Lv')->get_lv_level($udata['exp']);
        }
        $this->where('uid=' . $uid)->save($udata);
        D("LogGold")->add_log($type, $uid, $var, $logtxt, $addition);//增加变更日志
        return true;
    }

    /**
     * 增加点赞
     *
     * @param string $uid
     * @return bool
     */
    public function inc_praise($uid = '')
    {
        $map['uid'] = intval($uid);
        $this->where($map)->setInc('count_praise', 1);
        return true;
    }

    /**
     * 计算完成的百分比(会员中心经验进度条)
     *
     * @param $v1
     * @param $v2
     * @return string
     */
    public function get_exp_percentage($v1, $v2)
    {
        $percentage = $v1 / $v2;
        return round($percentage * 100) . '%';
    }

    /**
     * 修改用户名
     *
     * @param string $uid
     * @param string $username
     * @return mixed
     */
    public function edit_username($uid = '', $username = '')
    {
        $map['uid'] = array('NEQ', $uid);
        $map['username'] = $username;
        $info = $this->where($map)->find();
        if (empty($info)) {
            $map['uid'] = $uid;
            $map['username'] = $username;
            if (!$savearr = $this->create($map, 2)) {
                $return['status'] = 0;
                $return['content'] = $this->getError();
                return $return;
            }
            $this->save($savearr);
            $return['status'] = 1;
            $return['content'] = $map['username'];
            return $return;
        }
        $return['status'] = 0;
        $return['content'] = '用户名已经存在';
        return $return;
    }

    /**
     * 修改手机号
     *
     * @param string $uid
     * @param string $mobile
     * @return mixed
     */
    public function edit_mobile($uid = '', $mobile = '')
    {
        $map['uid'] = array('NEQ', $uid);
        $map['mobile'] = $mobile;
        $info = $this->where($map)->find();
        if (empty($info)) {
            $data['uid'] = $uid;
            $data['mobile'] = $mobile;
            $this->save($data);
            $return['status'] = 1;
            $return['content'] = $data['mobile'];
            return $return;
        } else {
            $return['status'] = 0;
            $return['content'] = "手机号{$mobile}已经被其他会员占用。";
            return $return;
        }
    }

    /**修改头像
     *
     * @param string $uid
     * @param string $avatar
     * @return bool
     */
    public function edit_avatar($uid = '', $avatar = '')
    {
        $map['uid'] = intval($uid);
        $map['avatar'] = trim($avatar);
        $this->save($map);
        return true;
    }

    /**
     * 获取默认头像以及隐藏手机等
     *
     * @param array|string $info
     * @return array|false
     */
    public function auto_user_fill($info = '')
    {
        if (empty($info)) {
            return false;
        }
        if ($info['avatar'] == '') {
            $info['avatar'] = __ROOT__ . '/' . C('YTATA_IMG_AVATAR_DIR') . 'avatar.jpg';
        } else {
            if (!is_http($info['avatar'])) {
                $info['avatar'] = __ROOT__ . '/' . C('YTATA_IMG_AVATAR_DIR') . $info['avatar'];
            }
        }
        $info['reg_time_str'] = daterange($info['reg_time']);
        $info['last_login_time_str'] = $info['last_login_time'] ? daterange($info['last_login_time']) : '无记录';
        $info['mobile_txt'] = $this->mobile_hide($info['mobile']);
        $info['user_url'] = $this->user_url($info['uid']);

        $nickname = $info['nick'];
        if (empty($nickname)) {
            $nickname = $info['mobile_txt'];
        }
        if (empty($nickname)) {
            $nickname = $info['username'];
        }
        if (empty($nickname)) {
            $nickname = '外星人';
        }
        $info['nickname'] = $nickname;

        return $info;
    }

    /**
     * 手机号加密
     *
     * @param string $mobile
     * @return string
     */
    public function mobile_hide($mobile)
    {
        if (empty($mobile)) {
            return '';
        }
        return substr($mobile, 0, 3) . '*****' . substr($mobile, 8);
    }

    /**
     * 检测用户名长度
     *
     * @param $str
     * @param $min
     * @param $max
     * @return bool
     */
    public function checklength($str, $min, $max)
    {
        //preg_match_all("/./u", $str, $matches);
        $len = mb_strlen($str, 'utf8');
        if ($len < $min || $len > $max) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 获取列表
     *
     * @param string $map
     * @param bool   $page
     * @param string $sort
     * @param string $num
     * @return mixed
     */
    public function get_list($map = '', $page = false, $sort = '', $num = '')
    {
        $limit = $num ? $num : 10;
        if (empty($sort)) {
            $sort = 'uid DESC';
        }
        if ($page) {
            $count = $this->where($map)->count();
            $Page = pager($count, $limit);
            $limit = $Page->firstRow . ',' . $Page->listRows;
            $page_str = $Page->fshow();
        }
        $result = $this->where($map)->order($sort)->limit($limit)->select();
        foreach ($result as $key => $v) {
            $v = $this->auto_user_fill($v);
            $v['reg_time_str'] = daterange($v['reg_time']);
            $v['last_login_time_str'] = daterange($v['last_login_time']);
            $v['ban'] = D('UserBan')->chenk_ban($v['uid']);
            $v['url'] = $this->user_url($v['uid']);
            $list[] = $v;
        }
        $return['list'] = $list;
        $return['page'] = $page_str;
        //print_r($return);
        return $return;
    }

    /**
     * 设置管理员
     *
     * @param int $uid
     * @param int $isadmin
     * @return bool
     */
    public function set_isadmin($uid, $isadmin = 0)
    {
        if ($uid && preg_match("/^(\d{1,10},)*(\d{1,10})$/", $uid)) {
            $data['isadmin'] = intval($isadmin);
            $map['uid'] = array('IN', $uid);
            $this->where($map)->save($data);
            return true;
        }
        return false;
    }

    /**
     * 删除会员（同时删除相关资料）
     *
     * @param string $uid
     * @return bool
     */
    public function del_user($uid = '')
    {
        $ids = is_array($uid) ? implode(",", $uid) : $uid;
        if ($ids && preg_match("/^(\d{1,10},)*(\d{1,10})$/", $ids)) {
            $map['uid'] = array('IN', $ids);
            $this->where($map)->delete();
            M('UserBan')->where($map)->delete();
            M('UserMsg')->where($map)->delete();
            M('UserMsgReply')->where($map)->delete();
            M('QuestionTag')->where($map)->delete();
            M('QuestionSupp')->where($map)->delete();
            M('QuestionImg')->where($map)->delete();
            M('Question')->where($map)->delete();
            M('LogTask')->where($map)->delete();
            M('LogLogin')->where($map)->delete();
            M('LogGold')->where($map)->delete();
            M('ArticleTag')->where($map)->delete();
            M('Article')->where($map)->delete();
            M('AnswerReply')->where($map)->delete();
            M('AnswerPraise')->where($map)->delete();
            M('Answer')->where($map)->delete();
            return true;
        }
        return false;

    }

    /**
     * 生成随机用户名
     * @param int    $len    随机码长度
     * @param string $prefix 生成用户名前缀
     * @return string
     */
    public function generate_username($len = 8, $prefix = 'mb')
    {
        if (!is_int($len) || $len < 1) {
            throw new \InvalidArgumentException('len参数必须为正整数');
        }
        do {
            $th = C('YTATA_REG_PRE_MOB');
            $th = $th ? $th : 'mb';
            $username_rand = $th . substr($mobile, -8, 8) . substr(uniqid(), -4, 4);
            //            $username_rand = $prefix . rand(pow(10, $len-1), pow(10, $len) - 1);
        } while ($this->get_user_one($username_rand, false, 3));
        return $username_rand;
    }

    /**
     * 修改点击次数
     *
     * @param string $uid
     * @return bool
     */
    public function edit_click($uid = '')
    {
        $map['uid'] = intval($uid);
        $this->where($map)->setInc('click', 1);
        return true;
    }

    /**
     * 获取用户展示地址
     *
     * @param int $uid 用户ID
     * @return string
     */
    public function user_url($uid)
    {
        return RU('u/view', array('uid' => $uid));
    }

    // 用户表更新前置操作
    protected function _before_update(&$data, $options)
    {
        if (isset($data['gold'])) {
            $list = $this->where($options['where'])->select();
            if ($list) {
                foreach ($list as $_data) {
                    $num = $data['gold'] - $_data['gold'];
                    if ($num > 0) {  // 只计算增，忽略减少
                        D('Rank')->add_record('gold', $_data['uid'], $num);
                    }
                }
            }
        }
    }
}